package com.itfreer.gis.server.utils.onlineTiles;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 定义远程切片下载类
 */
public class OnlineTiles {

	private static Map<SocketTimeoutException, String> tempMap = new HashMap<SocketTimeoutException, String>();

	/**
	 * 远程文件下载
	 *
	 * @param url  下载地址
	 * @param file 保存文件地址
	 */
	public static boolean download(String zxystr, URL url, File file) throws IOException {
		boolean flag = true;
		DataOutputStream dos = null;
		DataInputStream dis = null;
		try {
			if (!file.getParentFile().exists())
				file.getParentFile().mkdirs();
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
			conn.setConnectTimeout(6000);
			conn.setReadTimeout(20000);
			conn.connect();
			dos = new DataOutputStream(new FileOutputStream(file));
			dis = new DataInputStream(conn.getInputStream());
			byte[] data = new byte[2048];
			int i = 0;
			while ((i = dis.read(data)) != -1) {
				dos.write(data, 0, i);
			}
			dos.flush();
		} catch (SocketTimeoutException e) {
			tempMap.put(e, zxystr);
			System.out.println(zxystr);
			System.out.println(e);
		} catch (IOException e) {
			flag = false;
			System.out.println(e);
		} catch (Exception e) {
			flag = false;
			System.out.println(e);
		} finally {
			if (dis != null)
				dis.close();
			if (dos != null)
				dos.close();
		}
		return flag;
	}

	/**
	 * 根据经度获取切片规范下的行号
	 *
	 * @param lon
	 * @param zoom
	 * @return
	 */
	public static int getOSMTileXFromLongitude(double lon, int zoom) {
		return (int) (Math.floor((lon + 180) / 360 * Math.pow(2, zoom)));
	}

	/**
	 * 根据纬度获取切片规范下的列号
	 *
	 * @param lat
	 * @param zoom
	 * @return
	 */
	public static int getOSMTileYFromLatitude(double lat, int zoom) {
		return (int) (Math
				.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2
						* Math.pow(2, zoom)));
	}

	public static void start(String basePath, String name, String tilesUrl, double[] extent, int minZ, int maxZ)
			throws IOException {
		for (int z = minZ; z <= maxZ; z++) {
			// 计算行列号(使用瓦片的中心点经纬度计算)
			// 起始结束行
			int minR = getOSMTileYFromLatitude(extent[3], z);
			int maxR = getOSMTileYFromLatitude(extent[1], z);
			// 起始结束列
			int minC = getOSMTileXFromLongitude(extent[0], z);
			int maxC = getOSMTileXFromLongitude(extent[2], z);

			String path = "";
			String reTilesUrl = "";
			
			for (int y = minR; y <= maxR; y++) {
				for (int x = minC; x <= maxC; x++) {
					reTilesUrl = tilesUrl.replace("{z}", z + "").replace("{x}", x + "").replace("{y}", y + "");

					path = getFileUrl(basePath, name, x, y, z);

					File file = new File(path);
					URL url = new URL(reTilesUrl);
					DecimalFormat df = new DecimalFormat("0.00");
					System.out.println("X:(" + minC + "->" + maxC + "); Y:(" + minR + "->" + maxR + ")。");
					System.out.println("第" + z + "级总共将会有：" + (maxC - minC + 1) + "个文件夹，每个有" + (maxR - minR + 1)
							+ "个文件;总下载：" + (maxC - minC + 1) * (maxR - minR + 1) + "个文件；该级别下载进度："
							+ df.format(100 * (y - minR) / (double) (maxR - minR + 1)) + "%");
					System.out.println(reTilesUrl);
					String zxyStr = z + "/" + x + "/" + y;
					download(zxyStr, url, file);
				}
			}
		}
		System.out.println(
				"*******************************************"+tilesUrl+"下载结束了***********************************************************");
		Iterator<SocketTimeoutException> iterator = tempMap.keySet().iterator();
		while (iterator.hasNext()) {
			Object key = iterator.next();
			System.out.println("tmp.get(key) is :" + tempMap.get(key));
		}
	}

	public static String getFileUrl(String basePath, String name, int x, int y, int z) {
		String path = basePath + name + "/" + z + File.separator + x + File.separator + y;
		return path;
	}
}
